﻿using System;
using System.Collections.Generic;

namespace Allegro.TaskExecution
{
    /// <summary>
    /// Activity
    /// </summary>
    public abstract class TaskActivity : PersistentItem, ITaskActivity
    {
        /// <summary>
        /// method to check if task execution has been suspended or aborted
        /// </summary>
        /// <param name="context"></param>
        protected void CheckIfSuspendedOrAborted(IExecutionContext context)
        {
            ITaskContextCoordination coordination = context as ITaskContextCoordination;
            if(coordination != null)
            {
                coordination.ExitIfJobIsAborted();
                coordination.WaitIfJobIsSuspended();
            }
        }
    }

    /// <summary>
    /// Atomic task activity
    /// </summary>
    public abstract class AtomicTaskActivity : TaskActivity, IAtomicTaskActivity
    {
        /// <summary>
        /// Return true if the task can execute. Default is true
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public virtual bool CanExecute(IExecutionContext context)
        {
            return true;
        }
        /// <summary>
        /// Execute activity
        /// </summary>
        /// <param name="spawningTask"></param>
        /// <param name="context"></param>
        public void Execute(ITask spawningTask, IExecutionContext context)
        {
            // Check if job is execution is suspended or aborted prior to activity execution
            CheckIfSuspendedOrAborted(context);

            // Execute
            ExecuteActivity(spawningTask, context);

            // Check if job is execution is suspended or aborted after activity execution
            CheckIfSuspendedOrAborted(context);
        }
        /// <summary>
        /// Overridable method to execute the activity
        /// </summary>
        /// <param name="spawningTask"></param>
        /// <param name="context"></param>
        protected abstract void ExecuteActivity(ITask spawningTask, IExecutionContext context);
    }

    /// <summary>
    /// Composite task activity
    /// </summary>
    public abstract class CompositeActivity : TaskActivity, ICompositeTaskActivity
    {
        /// <summary>
        /// Called before a composite task is executed
        /// </summary>
        /// <param name="spawningTask"></param>
        /// <param name="context"></param>
        public void BeforeExecute(ITask spawningTask, IExecutionContext context)
        {
            // Check if job is execution is suspended or aborted prior to activity execution
            CheckIfSuspendedOrAborted(context);

            PreExecute(spawningTask, context);
        }
        /// <summary>
        /// Called after a composite task is executed
        /// </summary>
        /// <param name="spawningTask"></param>
        /// <param name="context"></param>
        public void AfterExecute(ITask spawningTask, IExecutionContext context)
        {
            // Check if job is execution is suspended or aborted prior to activity execution
            CheckIfSuspendedOrAborted(context);

            PostExecute(spawningTask, context);           
        }
        /// <summary>
        /// Overridable method for pre processing child task of a composite task
        /// </summary>
        /// <param name="spawningTask"></param>
        /// <param name="childTask"></param>
        /// <param name="currentActivityContext"></param>
        /// <param name="childActivityContext"></param>
        public virtual void PreProcessChildTask(ITask spawningTask, ITask childTask, IExecutionContext currentActivityContext, IExecutionContext childActivityContext)
        {
            
        }
        /// <summary>
        /// Overridable method for post processing child task of a composite task
        /// </summary>
        /// <param name="spawningTask"></param>
        /// <param name="childTask"></param>
        /// <param name="currentActivityContext"></param>
        /// <param name="childActivityContext"></param>
        public virtual void PostProcessChildTask(ITask spawningTask, ITask childTask, IExecutionContext currentActivityContext, IExecutionContext childActivityContext)
        {
            
        }
        /// <summary>
        /// Called before the first child task is invoked
        /// </summary>
        /// <param name="spawningTask"></param>
        /// <param name="context"></param>
        protected abstract void PreExecute(ITask spawningTask, IExecutionContext context);

        /// <summary>
        /// Called after the last child task has completed
        /// </summary>
        /// <param name="spawningTask"></param>
        /// <param name="context"></param>
        protected abstract void PostExecute(ITask spawningTask, IExecutionContext context);
    }
}
